<?php

declare(strict_types=1);

namespace seecms\controller;

use seecms\lib\builder\control\CheckboxControl;
use seecms\lib\builder\control\InputControl;
use seecms\db\SeeDbException;
use seecms\See;
use seecms\lib\Operate;
use seecms\lib\UserPermission;
use seecms\SeeConst;
use seecms\SeeLang;
use magein\utils\Tree;

class Permission extends SeeBaseController
{

    /**
     * @rule_title 菜单管理
     * @return string
     */
    public function menu(): string
    {
        $records = See::table()->menu->order('sort', 'asc')->select();

        $tree = Tree::init($records);
        $data = $tree->floor();

        return $this->view('permission/menu', [
            'menus' => $data
        ]);
    }

    /**
     * @rule_title 保存菜单排序
     * @return array
     * @throws SeeDbException
     */
    public function setMenuSort(): array
    {
        $id = See::request()->post('id');
        $sort = intval(See::request()->post('sort'));

        if (empty($id)) {
            return $this->fail(Operate::required());
        }

        if ($sort <= 0) {
            $sort = 1;
        }

        if ($sort > 99999) {
            $sort = 99999;
        }

        See::table()->menu->save(compact('id', 'sort'));

        return $this->saveSuccess();
    }


    /**
     * @rule_title 设置菜单状态
     * @return array
     * @throws SeeDbException
     */
    public function setMenuStatus(): array
    {
        $id = See::request()->post('id');
        $status = intval(See::request()->post('status'));

        if (empty($id)) {
            return $this->fail(Operate::required());
        }

        $status = $status === 1 ? 1 : 0;

        See::table()->menu->save(compact('id', 'status'));

        return $this->saveSuccess();
    }

    /**
     * @return string
     * @throws SeeDbException
     */
    public function userGrant(): string
    {
        $user_id = See::request()->param('id');

        $permission = UserPermission::init($user_id);

        // 用户权限
        $user_roles = $permission->role() ?: [];
        $user_menus = $permission->menu() ?: [];
        $has_rules = $permission->rule() ?: [];

        // 角色
        $roles = See::table()->user_role->select();
        // 菜单
        $menus = See::table()->menu->where('status', SeeConst::STATUS_OPEN)->order('sort', 'asc')->select();
        $menus = Tree::init($menus)
            ->setChild('children')
            ->transfer(function ($item) use ($user_menus) {
                $checked = false;
                if ($item['parent_id'] && in_array($item['id'], $user_menus)) {
                    $checked = true;
                }
                return [
                    'id' => $item['id'],
                    'parent_id' => $item['parent_id'],
                    'title' => $item['title'],
                    'spread' => true,
                    'checked' => $checked,
                ];
            });

        // 权限
        $rules = See::table()->user_rule->select();
        $group_rules = [];
        foreach ($rules as $rule) {
            $group_rules[$rule['group']][] = $rule;
        }

        return $this->view('permission/user.grant',
            compact(
                'roles',
                'user_id',
                'menus',
                'user_roles',
                'group_rules',
                'has_rules'
            ));
    }

    /**
     * @rule_title 保存用户角色
     * @return array
     * @throws SeeDbException
     */
    public function saveUserRoles(): array
    {
        $user_id = See::request()->post('user_id');
        $role_ids = See::request()->post('role_ids');

        if (empty($user_id) || empty($role_ids)) {
            return $this->fail(Operate::required('user_id,role_ids'));
        }

        $role_ids = array_filter(array_unique($role_ids));

        $result = See::table()->user_permission->updateOrCreate(compact('user_id'), ['role' => implode(',', $role_ids)]);

        if ($result >= 0) {
            return $this->saveSuccess();
        }

        return $this->saveFail();
    }


    /**
     * @rule_title 保存用户菜单
     * @return array
     */
    public function saveUserMenus(): array
    {
        $user_id = See::request()->post('user_id');
        $menu_ids = See::request()->post('menu_ids');

        if (empty($user_id) || empty($menu_ids)) {
            return $this->fail(Operate::required('user_id,menu_ids'));
        }

        $menu_ids = array_filter(array_unique($menu_ids));

        $result = See::table()->user_permission
            ->updateOrCreate(compact('user_id'), ['menu' => implode(',', $menu_ids)]);

        if ($result >= 0) {
            return $this->saveSuccess();
        }

        return $this->saveFail();
    }


    /**
     * @rule_title 保存用户权限
     * @return array
     */
    public function saveUserRules(): array
    {
        $user_id = See::request()->post('user_id');
        $rule_ids = See::request()->post('rule_ids');

        if (empty($user_id) || empty($rule_ids)) {
            return $this->fail(Operate::required('user_id、rule_ids'));
        }

        $rule_ids = array_filter(array_unique($rule_ids));

        $result = See::table()->user_permission
            ->updateOrCreate(compact('user_id'), ['rule' => implode(',', $rule_ids)]);

        if ($result >= 0) {
            return $this->saveSuccess();
        }

        return $this->saveFail();
    }

    /**
     * @rule_title 角色授权
     * @return string
     */
    public function roleGrant()
    {
        $role_id = See::request()->param('id');

        $role = See::table()->user_role->find($role_id);

        $role_menus = $role ? explode(',', $role['menu']) : [];
        $has_rules = $role ? explode(',', $role['rule']) : [];

        $menus = See::table()->menu->where('status', SeeConst::STATUS_OPEN)->order('sort', 'asc')->select();

        $data = Tree::init($menus)->setChild('children')->transfer(function ($item) use ($role_menus) {
            $checked = false;
            if ($item['parent_id'] && in_array($item['id'], $role_menus)) {
                $checked = true;
            }

            return [
                'id' => $item['id'],
                'parent_id' => $item['parent_id'],
                'title' => $item['title'],
                'spread' => true,
                'checked' => $checked,
            ];
        });

        // 获取权限
        $rules = See::table()->user_rule->select();
        $group_rules = [];
        foreach ($rules as $rule) {
            $group_rules[$rule['group']][] = $rule;
        }

        return $this->view('permission/role.grant', [
            'id' => $role_id,
            'menus' => $data,
            'group_rules' => $group_rules,
            'has_rules' => $has_rules,
        ]);
    }

    /**
     * @rule_title 保存角色菜单
     * @return array
     */
    public function saveRoleMenus(): array
    {
        $id = See::request()->post('id');
        $menu_ids = See::request()->post('menu_ids');

        if (empty($menu_ids)) {
            return $this->fail(SeeLang::permission('select_menus'));
        }

        if ($id == 1) {
            return $this->fail(SeeLang::permission('root_not_grant_menu'));
        }

        $record = See::table()->user_role->find($id);
        if (empty($record)) {
            return $this->fail(SeeLang::user('not_found'));
        }

        $menu_ids = array_filter(array_unique($menu_ids));

        // 更新角色的菜单信息
        See::table()->user_role->where('id', $id)->data('menu', implode(',', $menu_ids))->update();

        return $this->saveSuccess();
    }

    /**
     * @rule_title 保存角色权限
     * @return array
     */
    public function saveRoleRules(): array
    {
        $id = See::request()->post('id');
        $rule_ids = See::request()->post('rule_ids');

        if (empty($rule_ids)) {
            return $this->fail(SeeLang::permission('select_rules'));
        }

        if ($id == 1) {
            return $this->fail(SeeLang::permission('root_not_grant_rules'));
        }

        $record = See::table()->user_role->find($id);
        if (empty($record)) {
            return $this->fail(SeeLang::user('not_found'));
        }

        $rule_ids = array_filter(array_unique($rule_ids));

        // 更新角色的权限信息
        See::table()->user_role->where('id', $id)->data('rule', implode(',', $rule_ids))->update();

        return $this->saveSuccess();
    }

    public function resourceRule(): string
    {
        $options = [
            'index' => 'index',
            'read' => 'read',
            'create' => 'create',
            'save' => 'save',
            'edit' => 'edit',
            'update' => 'update',
            'delete' => 'delete',
        ];

        $controls = [
            InputControl::init('group')->setLabel(SeeLang::rule('group'))->setDescription([SeeLang::rule('group_tip')]),
            InputControl::init('title')->setLabel(SeeLang::rule('title'))->setDescription([SeeLang::rule('title_tip')]),
            CheckboxControl::init('resource')->setLabel(SeeLang::rule('resource'))->setOptions($options)->setDescription(
                [
                    SeeLang::rule('res_index_tip'),
                    SeeLang::rule('res_read_tip'),
                    SeeLang::rule('res_create_tip'),
                    SeeLang::rule('res_save_tip'),
                    SeeLang::rule('res_edit_tip'),
                    SeeLang::rule('res_update_tip'),
                    SeeLang::rule('res_delete_tip'),
                ]
            ),
        ];

        return $this->view('permission/resource', [
            'btn' => true,
            'action' => auth_route('permission/saveResourceRule'),
            'controls' => $controls
        ]);
    }

    public function saveResourceRule(): array
    {
        $group = See::request()->post('group');
        $title = See::request()->post('title');
        $resource = See::request()->post('resource');

        if (empty($group)) {
            return $this->fail(SeeLang::rule('enter_group'));
        }

        if (empty($title)) {
            return $this->fail(SeeLang::rule('enter_title'));
        }

        $resource = array_filter($resource);
        if (empty($resource)) {
            return $this->fail(SeeLang::rule('select_resource'));
        }

        $options = [
            'page' => '%s' . SeeLang::rule('resource_page'),
            'index' => '%s' . SeeLang::rule('resource_index'),
            'read' => '%s' . SeeLang::rule('resource_read'),
            'create' => SeeLang::rule('resource_create') . '%s',
            'save' => SeeLang::rule('resource_save') . '%s',
            'edit' => SeeLang::rule('resource_edit') . '%s',
            'update' => SeeLang::rule('resource_update') . '%s',
            'delete' => SeeLang::rule('resource_delete') . '%s',
        ];

        $group = trim($group);
        $group = trim($group, '/');

        foreach ($resource as $item) {
            $url = 'p/' . $group . '/' . $item;
            $record = See::table()->user_rule->where('url', $url)->find();

            if (empty($record)) {
                See::table()->user_rule->insert([
                    'group' => $group,
                    'title' => sprintf($options[$item], $title),
                    'url' => $url,
                ]);
            }
        }

        return $this->saveSuccess();
    }
}